use std::str::FromStr;

use serde::{Deserialize, Serialize};

use crate::{models::ChatFile, AppError, AppState};

use chat_core::Message;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateMessage {
    pub content: String,
    pub file: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListMessage{
    pub chat_id: u64,
    pub last_id: Option<u64>,
    pub limit: u64,
}
#[allow(dead_code)]
impl AppState {
    pub async fn create_message(&self,input: CreateMessage,ws_id: u64,user_id: u64) -> Result<Message, AppError> {
        let base_dir = &self.config.server.base_dir;
        if input.content.is_empty() {
            return Err(AppError::CreateMessageError("content is empty".to_string()));
            
        }
        for s in &input.file {
            let file = ChatFile::from_str(s)?;
            let path = file.path(base_dir);
            if !path.exists() {
                return Err(AppError::CreateMessageError(format!("file not found:{}",s)));
            }
        }
        // if !self.is_chat_member(ws_id,user_id).await? {
        //     return Err(AppError::CreateMessageError("You are not a member of this chat".to_string()));
            
        // }
        let message: Message = sqlx::query_as(
            r#"
            INSERT INTO messages(chat_id,sender_id,content,files)
            VALUES($1,$2,$3,$4)
            RETURNING id,chat_id,sender_id,content,files,created_at
            "#
        ).bind(ws_id as i32)
        .bind(user_id as i32)
        .bind(&input.content)
        .bind(&input.file)
        .fetch_one(&self.inner.pool)
        .await?;
    Ok(message)
    }

    pub async fn list_messages(
        &self,
        input: ListMessage,
        chat_id: u64,
    ) -> Result<Vec<Message>, AppError> {
        let last_id = input.last_id.unwrap_or(i64::MAX as _);

        let messages: Vec<Message> = sqlx::query_as(
            r#"
        SELECT id, chat_id, sender_id, content, files, created_at
        FROM messages
        WHERE chat_id = $1
        AND id < $2
        ORDER BY id DESC
        LIMIT $3
        "#,
        )
        .bind(chat_id as i64)
        .bind(last_id as i64)
        .bind(input.limit as i64)
        .fetch_all(&self.pool)
        .await?;

        Ok(messages)
    }
}


#[cfg(test)]
mod tests{
    use crate::AppConfig;

    use super::*;
    use anyhow::Result; 
    #[tokio::test]
    async fn list_message_should_work() -> Result<()>{
        // let (_tdb,state) = AppState::new_for_test().await?;
        let config = AppConfig::load()?;
        let state = AppState::try_new(config).await?;
        let input = ListMessage{
            chat_id: 1,
            last_id: None,
            limit: 10,
        };
        let messages = state.list_messages(input,1).await?;
        assert_eq!(messages.len(),0);
        Ok(())
    }
}